﻿using System;
using DataInterpolator.Model;
using OxyPlot;
using OxyPlot.Annotations;

namespace DataInterpolator.ViewModel
{
   public class InterpPairVMO
   {
      [Flags]
      public enum ActiveStates
      {
         None = 0,
         Left = 0x1,
         Right = 0x2
      };

      public event Action<InterpPairVMO, double> ValueChanged;
      public event Action<InterpPairVMO, ActiveStates> StateChanged;
      public event Action DoubleRightClick;

      private double _PrevVertVal = 0.0;
      private double _PrevHorizVal = 0.0;

      private PlotModel _PlotViewModel = null;
      private PointAnnotation _LeftPoint = new PointAnnotation();
      private LineAnnotation _LeftAnnotation = new LineAnnotation();
      private ArrowAnnotation _MiddleAnnotation = new ArrowAnnotation();
      private LineAnnotation _RightAnnotation = new LineAnnotation();
      private PointAnnotation _RightPoint = new PointAnnotation();

      public InterpPairVMO(PlotModel plotViewModel, InterpPair interpPair)
      {
         _PlotViewModel = plotViewModel;
         Pair = interpPair;

         _LeftAnnotation.XAxisKey = InterpolationViewModel.__LeftKey;
         _LeftAnnotation.Type = LineAnnotationType.Horizontal;
         _LeftAnnotation.TextHorizontalAlignment = HorizontalAlignment.Left;
         //_LeftAnnotation.TextLinePosition = 0.5;
         _LeftAnnotation.TextPadding = 0.1;
         _LeftAnnotation.FontSize = 16.0;
         _LeftAnnotation.FontWeight = 1.5;

         _LeftPoint.XAxisKey = InterpolationViewModel.__MiddleKey;
         _LeftPoint.Shape = MarkerType.Square;
         _LeftPoint.Size = 5;

         _MiddleAnnotation.XAxisKey = InterpolationViewModel.__MiddleKey;
         _MiddleAnnotation.HeadLength = 0.0;
         _MiddleAnnotation.HeadWidth = 0.0;

         _RightPoint.XAxisKey = InterpolationViewModel.__MiddleKey;
         _RightPoint.Shape = MarkerType.Square;
         _RightPoint.Size = 5;

         _RightAnnotation.XAxisKey = InterpolationViewModel.__RightKey;
         _RightAnnotation.Type = LineAnnotationType.Horizontal;
         _RightAnnotation.TextHorizontalAlignment = HorizontalAlignment.Center;
         _RightAnnotation.TextLinePosition = 0.5;
         _RightAnnotation.TextPadding = 0.1;
         _RightAnnotation.FontSize = 16.0;
         _RightAnnotation.FontWeight = 1.5;

         plotViewModel.Annotations.Add(_LeftAnnotation);
         plotViewModel.Annotations.Add(_LeftPoint);
         plotViewModel.Annotations.Add(_MiddleAnnotation);
         plotViewModel.Annotations.Add(_RightPoint);
         plotViewModel.Annotations.Add(_RightAnnotation);

         // Handle left mouse clicks
         _LeftAnnotation.MouseDown += AnnotationMouseDown;
         _LeftPoint.MouseDown += AnnotationMouseDown;
         _MiddleAnnotation.MouseDown += AnnotationMouseDown;
         _RightPoint.MouseDown += AnnotationMouseDown;
         _RightAnnotation.MouseDown += AnnotationMouseDown;

         // Handle mouse movements (note: this is only called when the mousedown event was handled)
         _LeftAnnotation.MouseMove += AnnotationMouseMove;
         _LeftPoint.MouseMove += AnnotationMouseMove;
         _MiddleAnnotation.MouseMove += AnnotationMouseMove;
         _RightPoint.MouseMove += AnnotationMouseMove;
         _RightAnnotation.MouseMove += AnnotationMouseMove;

         // Handle mouse up (note: this is only called when the mousedown event was handled)
         _LeftAnnotation.MouseUp += AnnotationMouseUp;
         _LeftPoint.MouseUp += AnnotationMouseUp;
         _MiddleAnnotation.MouseUp += AnnotationMouseUp;
         _RightPoint.MouseUp += AnnotationMouseUp;
         _RightAnnotation.MouseUp += AnnotationMouseUp;
      }

      public InterpPair Pair
      {
         get; set;
      }

      private ActiveStates _State = ActiveStates.None;

      /// <summary>
      /// Sets and gets the State property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      public ActiveStates State
      {
         get
         {
            return _State;
         }

         set
         {
            if (_State == value)
            {
               return;
            }

            ActiveStates oldState = _State;

            _State = value;

            if (StateChanged != null)
            {
               StateChanged(this, oldState);
            }
         }
      }

      private void AnnotationMouseDown(object sender, OxyMouseDownEventArgs e)
      {
         if (e.ChangedButton == OxyMouseButton.Right && e.ClickCount == 2)
         {
            if (DoubleRightClick != null)
            {
               DoubleRightClick();
            }
         }
         else if (e.ChangedButton != OxyMouseButton.Left)
         {
            return;
         }

         if (sender == _LeftAnnotation || sender == _LeftPoint)
         {
            State = ActiveStates.Left;
         }
         else if (sender == _MiddleAnnotation)
         {
            ActiveStates tempState = ActiveStates.Left;
            tempState |= (e.HitTestResult.Index != 2) ? ActiveStates.Left : ActiveStates.None;
            tempState |= (e.HitTestResult.Index != 1) ? ActiveStates.Right : ActiveStates.None;

            State = tempState;
         }
         else if (sender == _RightAnnotation || sender == _RightPoint)
         {
            State = ActiveStates.Right;
         }

         e.Handled = true;
      }

      private void AnnotationMouseMove(object sender, OxyMouseEventArgs e)
      {
         if (State == ActiveStates.None)
            return;

         var thisPoint = ((Annotation)sender).InverseTransform(e.Position);

         double dy = thisPoint.Y - _PrevVertVal;

         if (Math.Abs(dy) > 0.0)
         {
            _PrevHorizVal = (thisPoint.X - InterpolationViewModel.__MiddleAxisMinPad) / ((Properties.Settings.Default.InterpolationLevels + InterpolationViewModel.__MiddleAxisMaxPad) - InterpolationViewModel.__MiddleAxisMinPad);

            if (ValueChanged != null)
            {
               ValueChanged(this, dy);
            }
         }

         e.Handled = true;
      }

      private void AnnotationMouseUp(object sender, OxyMouseEventArgs e)
      {
         State = ActiveStates.None;
      }

      public void Refresh(double xOffset, double xScale)
      {
         double leftValue = Pair.Left * xScale + xOffset;
         double rightValue = Pair.Right * xScale + xOffset;

         _LeftAnnotation.Y = leftValue;

         _LeftPoint.X = 0.5;
         _LeftPoint.Y = leftValue;

         double countPlus = Properties.Settings.Default.InterpolationLevels + 0.5;
         _MiddleAnnotation.StartPoint = new DataPoint(0.5, leftValue);
         _MiddleAnnotation.EndPoint = new DataPoint(countPlus, rightValue);

         _RightPoint.X = countPlus;
         _RightPoint.Y = rightValue;

         _RightAnnotation.Y = rightValue;

         _MiddleAnnotation.Color = OxyColors.Blue;

         if ((State & ActiveStates.Left) > 0)
         {
            _LeftAnnotation.Text = leftValue.ToString();
            _LeftAnnotation.Color = OxyColors.Red;
            _LeftPoint.Fill = OxyColors.Red;

            _MiddleAnnotation.Color = OxyColors.Red;
         }
         else
         {
            _LeftAnnotation.Text = "";
            _LeftAnnotation.Color = OxyColors.Blue;
            _LeftPoint.Fill = OxyColors.Blue;
         }

         if ((State & ActiveStates.Right) > 0)
         {
            _RightAnnotation.Text = rightValue.ToString();
            _RightAnnotation.Color = OxyColors.Red;
            _RightPoint.Fill = OxyColors.Red;

            _MiddleAnnotation.Color = OxyColors.Red;
         }
         else
         {
            _RightAnnotation.Text = "";
            _RightAnnotation.Color = OxyColors.Blue;
            _RightPoint.Fill = OxyColors.Blue;
         }

         if (State == (ActiveStates.Left | ActiveStates.Right))
         {
            _PrevVertVal = (rightValue - leftValue) * _PrevHorizVal + leftValue;
         }
         else if ((State & ActiveStates.Left) > 0)
         {
            _PrevVertVal = leftValue;
         }
         else if ((State & ActiveStates.Right) > 0)
         {
            _PrevVertVal = rightValue;
         }
         else
         {
            _PrevVertVal = 0.0;
         }
      }

      public void RemoveFromPlot()
      {
         _PlotViewModel.Annotations.Remove(_LeftPoint);
         _PlotViewModel.Annotations.Remove(_LeftAnnotation);
         _PlotViewModel.Annotations.Remove(_MiddleAnnotation);
         _PlotViewModel.Annotations.Remove(_RightAnnotation);
         _PlotViewModel.Annotations.Remove(_RightPoint);
      }
   }


}
